<script setup>
import {
  getRoleListApi,
  addRoleApi,
  modifyRoleApi,
  deleteRoleApi,
  getRoleApi,
  assignPermApi
} from '@/api/role'
import { getPermListApi } from '@/api/permission'
import { transList2Tree } from '@/utils/date-handle'
import { nextTick, onMounted, ref } from 'vue'

// 角色列表
const rolelist = ref([])
const setRoleList = async () => {
  const res = await getRoleListApi()
  res.data.forEach((item) => {
    // 添加是否编辑属性
    item.isEdit = false
    // 缓存数据，用于编辑时回显，注意必须为深拷贝
    // item.editRow = item 这样写为浅拷贝，且存在循环引用问题
    // 因为item中的属性为基本类型和字符串，因此不存在深拷贝浅拷贝问题
    item.editRow = {
      roleName: item.roleName,
      roleCode: item.roleCode,
      status: item.status,
      roleDesc: item.roleDesc
    }
  })
  rolelist.value = res.data
}

// 添加角色对话框
const dialogVisable = ref(false)
const addRole = ref({
  roleName: '',
  roleCode: '',
  status: 0,
  roleDesc: ''
})
// 添加角色表单DOM
const addForm = ref(null)
// 关闭添加角色对话框
const closeDialog = () => {
  dialogVisable.value = false
  addForm.value.resetFields()
}
// 添加角色校验规则
const addFormRules = ref({
  roleName: [{ required: true, message: '角色名称不能为空', trigger: 'blur' }],
  roleCode: [{ required: true, message: '角色代码不能为空', trigger: 'blur' }],
  roleDesc: [{ required: true, message: '角色描述不能为空', trigger: 'blur' }]
})
// 添加角色
const addRoleBtn = () => {
  addForm.value.validate(async (isOk) => {
    if (isOk) {
      await addRoleApi(addRole.value)
      // 回显数据
      setRoleList()
      ElMessage.success('添加角色成功')
      closeDialog()
    }
  })
}

// 取消编辑按钮
const onCancelEdit = (row) => {
  // 恢复缓存数据
  row.editRow = {
    roleName: row.roleName,
    roleCode: row.roleCode,
    status: row.status,
    roleDesc: row.roleDesc
  }
  // 关闭编辑
  row.isEdit = false
}

// 确认编辑按钮
const onModify = async (row) => {
  // name和desc字段校验
  if (row.editRow.roleName && row.editRow.roleCode && row.editRow.roleDesc) {
    // 提交数据
    await modifyRoleApi({ id: row.id, ...row.editRow })
    ElMessage.success('修改成功')
    // 将当前row的相关属性改为修改之后的
    // 注意，和Java一样，形参的引用不能更改，这种写法是错的
    // 错误写法：row = { ...row.editRow, isEdit: false }
    Object.assign(row, { ...row.editRow, isEdit: false })
  } else {
    ElMessage.error('角色名称或角色描述或角色代码不能为空')
  }
}
// 删除角色
const deleteRole = async (id) => {
  // 调用接口删除
  await deleteRoleApi(id)
  ElMessage.success('删除成功')
  // 重载数据
  setRoleList()
}

// 分配权限树形控件DOM
const permTree = ref(null)
// 分配权限树形数据
const permTreeData = ref([])
const permDialogVisable = ref(false)
// 分配权限时的角色id
const assignId = ref('')

// 分配权限按钮
const openAssignPerm = async (id) => {
  assignId.value = id
  // 打开加载
  const loading = ElLoading.service({
    lock: true,
    text: 'Loading',
    spinner: 'el-icon-loading',
    background: 'rgba(0, 0, 0, 0.7)'
  })
  try {
    // 获取权限列表，转为树形数据
    const res = await getPermListApi()
    permTreeData.value = transList2Tree(res.data)

    // 回显用户的角色
    const res2 = await getRoleApi(id)
    // 等数据准备完毕再关闭加载、打开框
    permDialogVisable.value = true // 这行放后面会导致setCheckedKeys方法异常
    nextTick(() => {
      permTree.value.setCheckedKeys(res2.data)
    })
  } finally {
    // 防止出现异常
    loading.close()
  }
}

// 确定分配权限
const assignPerm = async () => {
  const keys = permTree.value.getCheckedKeys()
  if (keys.length > 0) {
    await assignPermApi({
      id: assignId.value,
      permIdList: keys
    })
    ElMessage.success('分配权限成功')
    permDialogVisable.value = false
  } else {
    ElMessage.error('请至少分配一个权限')
  }
}

onMounted(() => setRoleList())
</script>

<template>
  <div class="container">
    <div class="app-container">
      <!-- 添加角色对话框 -->
      <el-dialog
        title="添加角色"
        width="400"
        v-model="dialogVisable"
        @close="closeDialog"
      >
        <el-form
          ref="addForm"
          :model="addRole"
          :rules="addFormRules"
          label-width="80px"
          size="small"
        >
          <el-form-item label="角色名称" prop="roleName">
            <el-input v-model="addRole.roleName" type="text" />
          </el-form-item>
          <el-form-item label="角色代码" prop="roleCode">
            <el-input v-model="addRole.roleCode" type="text" />
          </el-form-item>
          <el-form-item label="启用">
            <el-switch
              v-model="addRole.status"
              :active-value="1"
              :inactive-value="0"
            />
          </el-form-item>
          <el-form-item label="描述" prop="roleDesc">
            <el-input v-model="addRole.roleDesc" type="textarea" />
          </el-form-item>
          <el-form-item>
            <el-row type="flex" justify="center">
              <el-button type="primary" @click="addRoleBtn">确定</el-button>
              <el-button @click="closeDialog">取消</el-button>
            </el-row>
          </el-form-item>
        </el-form>
      </el-dialog>
      <div style="padding: 20px">
        <!-- 添加角色按钮 -->
        <div class="add-role-btn">
          <el-button type="primary" size="small" @click="dialogVisable = true"
            >添加角色</el-button
          >
        </div>
        <!-- 角色列表表格 -->

        <el-table :data="rolelist">
          <el-table-column label="角色名称">
            <template #default="{ row }">
              <el-input
                v-if="row.isEdit"
                v-model="row.editRow.roleName"
                type="text"
                size="mini"
              />
              <span v-else>{{ row.roleName }}</span>
            </template>
          </el-table-column>
          <el-table-column label="角色代码">
            <template #default="{ row }">
              <el-input
                v-if="row.isEdit"
                v-model="row.editRow.roleCode"
                type="text"
                size="mini"
              />
              <span v-else>{{ row.roleCode }}</span>
            </template>
          </el-table-column>
          <el-table-column label="状态">
            <template #default="{ row }">
              <el-switch
                v-if="row.isEdit"
                v-model="row.editRow.status"
                :active-value="1"
                :inactive-value="0"
                size="mini"
              />
              <span v-else>
                {{
                  row.status === 1 ? '启用' : row.status === 0 ? '禁用' : '无'
                }}
              </span>
            </template>
          </el-table-column>
          <el-table-column label="描述">
            <template #default="{ row }">
              <el-input
                v-if="row.isEdit"
                v-model="row.editRow.roleDesc"
                type="textarea"
                :rows="1"
                size="mini"
              />
              <span v-else>{{ row.roleDesc }}</span>
            </template> </el-table-column
          >>
          <el-table-column label="操作">
            <template #default="{ row }">
              <el-row v-if="row.isEdit">
                <el-button type="primary" size="mini" @click="onModify(row)"
                  >确定</el-button
                >
                <el-button size="mini" @click="onCancelEdit(row)"
                  >取消</el-button
                >
              </el-row>
              <el-row justify="start" v-else>
                <el-col :span="5">
                  <el-link
                    size="small"
                    type="primary"
                    @click.prevent="openAssignPerm(row.id)"
                    >权限</el-link
                  >
                </el-col>
                <el-col :span="5">
                  <el-link
                    style="margin-right: 10px"
                    size="small"
                    type="primary"
                    @click.prevent="row.isEdit = true"
                    >编辑</el-link
                  >
                </el-col>
                <el-col :span="5">
                  <el-popconfirm
                    title="确定删除吗？"
                    @confirm="deleteRole(row.id)"
                  >
                    <template #reference>
                      <el-link size="small" type="primary">删除</el-link>
                    </template>
                  </el-popconfirm>
                </el-col>
              </el-row>
            </template>
          </el-table-column>
        </el-table>
      </div>
      <!-- 分配权限对话框 -->
      <el-dialog title="权限" width="450" v-model="permDialogVisable">
        <el-tree
          ref="permTree"
          :data="permTreeData"
          node-key="id"
          default-expand-all
          show-checkbox
          :props="{ children: 'children', label: 'name' }"
          check-strictly
        />
        <template #footer>
          <el-row justify="center" type="flex">
            <el-button size="small" type="primary" @click="assignPerm"
              >确定</el-button
            >
            <el-button size="small" @click="permDialogVisable = false"
              >取消</el-button
            >
          </el-row>
        </template>
      </el-dialog>
    </div>
  </div>
</template>

<style scoped>
.container {
  background-color: #fff;
  min-height: 650px;
}
.app-container {
  padding: 0 20px;
}
.add-role-btn {
  padding-bottom: 15px;
  position: relative;
  left: -10px;
}
</style>
